﻿using UnityEngine;
using System.Collections;
using UnityEngine.Profiling;
using System.Text;
using Unity.Profiling;

public class Fps : MonoBehaviour
{
    float updateInterval = 0.25f;

    private float passed = 0;

    ProfilerRecorder mainThreadTimeRecorder;
    ProfilerRecorder systemMemoryRecorder;
    ProfilerRecorder gcMemoryRecorder;
    ProfilerRecorder drawCallsRecorder;
    ProfilerRecorder vertRecorder;
    ProfilerRecorder trisRecorder;
    ProfilerRecorder batchesRecorder;
    ProfilerRecorder savedbatchesRecorder;
    ProfilerRecorder skinnedmeshRecorder;

    ProfilerRecorder setPassCallRecorder;
    ProfilerRecorder shadowCastersRecorder;

    string deviceModel, deviceName, graphicsMemorySize, graphicsName, maxTextureSize, systemMemorySize;

    string showInfo = "";

    void Awake()
    {
        passed = 0;

        deviceModel = SystemInfo.deviceModel;
        deviceName = SystemInfo.deviceName;
        graphicsMemorySize = $"{SystemInfo.graphicsMemorySize}MB";
        maxTextureSize = $"{SystemInfo.maxTextureSize}";
        systemMemorySize = $"{SystemInfo.systemMemorySize}MB";
        graphicsName = SystemInfo.graphicsDeviceName;
    }

    void OnEnable()
    {
        mainThreadTimeRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Internal, "Main Thread", 4);
        systemMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Total Used Memory");
        gcMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Total Reserved Memory");
        drawCallsRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Draw Calls Count");
        vertRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Vertices Count");
        trisRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Triangles Count");
        batchesRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Batches Count");
        setPassCallRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "SetPass Calls Count");

        skinnedmeshRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Visible Skinned Meshes Count");
        savedbatchesRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Saved By Batching Count");
        shadowCastersRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Shadow Casters Count");

    }

    void OnDisable()
    {
        mainThreadTimeRecorder.Dispose();
        systemMemoryRecorder.Dispose();
        gcMemoryRecorder.Dispose();
        drawCallsRecorder.Dispose();
        vertRecorder.Dispose();
        trisRecorder.Dispose();
        batchesRecorder.Dispose();
        setPassCallRecorder.Dispose();

        skinnedmeshRecorder.Dispose();
        savedbatchesRecorder.Dispose();

        shadowCastersRecorder.Dispose();
    }

    static double GetRecorderFrameAverage(ProfilerRecorder recorder)
    {
        var samplesCount = recorder.Capacity;
        if (samplesCount == 0)
            return 0;

        double r = 0;
        unsafe
        {
            var samples = stackalloc ProfilerRecorderSample[samplesCount];
            recorder.CopyTo(samples, samplesCount);
            for (var i = 0; i < samplesCount; ++i)
                r += samples[i].Value;
            r /= samplesCount;
        }

        return r;
    }

    void Update()
    {
        passed += Time.deltaTime;
        if (passed > updateInterval)
        {
            passed = 0;

            var newline = System.Environment.NewLine;
            var tmp = GetRecorderFrameAverage(mainThreadTimeRecorder);
            showInfo = $"{newline}" +
                $" {deviceModel}-{deviceName} SysMemory: {systemMemorySize} {newline}" +
                $" {graphicsName}（{graphicsMemorySize}）{newline}" +
                $" {newline}" +
                $" {1000000000.0f / tmp:f2}FPS（{tmp / 1000000.0f:f2}ms）{newline}" +
                $" Draw Call: {drawCallsRecorder.LastValue} {newline}" +
                $" Batches: {batchesRecorder.LastValue} " +
                $" Saved by batching: {savedbatchesRecorder.LastValue} {newline}" +
                $" Tris: {trisRecorder.LastValue}  Verts: {vertRecorder.LastValue} {newline}" +
                $" Screen: {Screen.width}*{Screen.height} " +
                $" MaxTextureSize: {maxTextureSize} {newline}" +
                $" SetPass calls: {setPassCallRecorder.LastValue} " +
                $" Shadow casters: {shadowCastersRecorder.LastValue} {newline}" +
                $" Visible skinned meshes: {skinnedmeshRecorder.LastValue} {newline}" +
                $" {newline}" +
                $" Used Mem: {GetFriendly(systemMemoryRecorder.LastValue)} " +
                $" Reserved Mem: {GetFriendly(gcMemoryRecorder.LastValue)} {newline}"
                ;
        }
    }

    private string GetFriendly(long length)
    {
        if (length < 1024)
        {
            return $"{length} B";
        }
        else if (length < 1024 * 1024)
        {
            return $"{length * 1.0f / 1024:f2} KB";
        }
        else if (length < 1024 * 1024 * 1024)
        {
            return $"{length * 1.0f / (1024 * 1024):f2} MB";
        }

        return $"{length * 1.0f / (1024 * 1024 * 1024):f2} GB";
    }

    private void OnGUI()
    {
        var style = GUI.skin.box;

        style.alignment = TextAnchor.MiddleLeft;
        style.fontSize = 24;

        var oldColr = GUI.contentColor;

        GUI.contentColor = Color.green;

        GUILayout.Box(showInfo, style);

        GUI.contentColor = oldColr;
    }
}
